/*********************************************
 * Student    : Teodoro Cipresso
 * Course     : CS286
 * Professor  : Vidya Setlur
 * Assignment : Term Project (BlueTanks)
 *********************************************/
package edu.sjsu.cs286.teodoro.cipresso.sprites;

import java.io.IOException;

import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.Sprite;
import javax.microedition.lcdui.game.TiledLayer;
import javax.microedition.media.MediaException;
import javax.microedition.media.Player;

import edu.sjsu.cs286.teodoro.cipresso.playfield.BlueTankGameCanvas;
import edu.sjsu.cs286.teodoro.cipresso.sound.BlueTankSoundHolder;

/**
 * Instances of this class represent a projectile fired from the players
 * cannons. The projectile can be fired in one of the 16 directions faceable by
 * the tanks. If the projectile detects a collision with an object, either a
 * wall or a ownerTank it will animate an explosion. If the collision target was
 * a Tank, armor points are deducted from the ownerTank.
 * 
 * @author Teodoro Cipresso
 */
public class BlueTankProjectileSprite extends Sprite implements IBlueTankSprite {

	BlueTankGameCanvas btCanvas = null;

	BlueTankVehicleSprite owningVehicle = null;

	BlueTankVehicleSprite targetVehicle = null;

	BlueTankVectorTraversal vectorMove = null;

	int cannonDirection;

	boolean exploding = false;

	boolean playSound = false;

	/**
	 * Default constructor. Creates new instance of tank projectile based on the
	 * properties of the owning sprite (tank that fired it). The new instance of
	 * the projectile sprite is inserted in the layer manager at the level
	 * closest to the user (most visible). The initial position of the
	 * projectile is based on the owning tank.
	 * 
	 * @param image,
	 *            the projectile image
	 * @param frameWidth,
	 *            the width of each frame in the image
	 * @param frameHeight,
	 *            the height of each frame in the image
	 * @param owningSprite,
	 *            the tank that owns the projectile (is firing it).
	 */
	public BlueTankProjectileSprite(Image image, int frameWidth,
			int frameHeight, BlueTankVehicleSprite owningSprite) {
		super(image, frameWidth, frameHeight);
		defineReferencePixel(frameWidth / 2, frameHeight / 2);
		// Set the projectiles vector based on the owning sprite
		this.cannonDirection = owningSprite.getCannonDirection();
		this.owningVehicle = owningSprite;
		// insert the projectile onto the game canvas
		btCanvas = owningSprite.getBtCanvas();
		btCanvas.getLayerManager().insert(this, 0);
		// position the projectile sprite based on the owning sprite
		setPosition(owningSprite.getX(), owningSprite.getY());
		vectorMove = new BlueTankVectorTraversal(this);
	} // BlueTankProjectileSprite()

	/**
	 * Update the state of the projectile. This method is called from the owning
	 * tank sprite object with the frequency based on the game update cycle
	 * delay of the game canvas
	 */
	public void update() {
		// move projectile along vectors if it hasn't collided with the wall or
		// tank
		if (!exploding) {
			vectorMove.vectorMove(cannonDirection,
					IBlueTankSprite.CANNON_BALL_SPEED);
			checkCollisions();
		} else {
			// if the explosion animation is complete, remove the sprite from
			// the canvas
			if ((getFrame() + 1) == getFrameSequenceLength()) {
				// remove from play
				btCanvas.getLayerManager().remove(this);
				owningVehicle.clearProjectile();
				// update the peer tank with weapon hit
				if (targetVehicle != null) {
					targetVehicle.handleWeaponCollision(true);
				}
			} else {
				// show the next frame in the explosion animation sequence
				nextFrame();
				// if this is the first frame, play the explosion sound
				if (playSound) {
					playSound = (!playSound);
					try {
						Player player = BlueTankSoundHolder
								.getCannonBallCollisionPlayer();
						player.stop();
						player.setMediaTime(0);
						player.start();
					} catch (MediaException e) {
						e.printStackTrace();
					}
				} // if play effect
			} // if last frame
		} // if not exploding
	} // update()

	/**
	 * This method checks for collisions between this projectile instance and
	 * the target tank (peer tank) as well as the impassable terrain.
	 */
	public void checkCollisions() {
		// check for collision with impassable terrain
		TiledLayer wall = btCanvas.getImpassableTerrain();
		if (collidesWith(wall, true)) {
			exploding = playSound = true;
		}
		// check for collision with other vehicles, this is tricky to think
		// about, but meaning of peer and self are flipped when replicating
		// state on other client
		targetVehicle = btCanvas.getPeerTank();
		if (targetVehicle.equals(owningVehicle)) {
			targetVehicle = btCanvas.getSelfTank();
		}
		if (collidesWith(targetVehicle, true)) {
			exploding = playSound = true;
		} else {
			targetVehicle = null;
		}
	} // checkCollisions()

	/**
	 * Static convenience method for creating instances of this class
	 * 
	 * @return new instance of this class, properly inited based on owning
	 *         sprite (tank)
	 */
	public static BlueTankProjectileSprite createProjectile(
			BlueTankVehicleSprite owningSprite) throws IOException {
		//
		return new BlueTankProjectileSprite(
				BlueTankImageHolder.getCannonBall(), 32, 32, owningSprite);
	} // createProjectile()

} // BlueTankProjectileSprite()
